<?php
/**
 * ePDQ CPI payment module
 *
 * @package payment modules
 * @copyright Copyright 2003-2008 Zen Cart Development Team
 * @copyright Portions Copyright 2003 osCommerce
 * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
 * @version $Id: epdq.php 263 2008-10-30 02:01:11Z kuroi $
 */

  class epdq extends base{
    public $code, $title, $description, $enabled;

    // class constructor
    function epdq() {
        global $order;

        $this->code 			= 'epdq';
    	$this->title			= MODULE_PAYMENT_EPDQ_TEXT_TITLE;
    	$this->description	 	= MODULE_PAYMENT_EPDQ_TEXT_DESCRIPTION;
    	$this->sort_order 		= MODULE_PAYMENT_EPDQ_SORT_ORDER;
    	$this->enabled		 	= MODULE_PAYMENT_EPDQ_STATUS;
    	$this->clientid = MODULE_PAYMENT_EPDQ_CLIENT_ID;
        $this->enabled = ((MODULE_PAYMENT_EPDQ_STATUS == 'True') ? true : false);
        
    	if($this->isOnePagePayment()) {
    		$landing_page = "pay.shtml";
    	} else {
    		$landing_page = "select.shtml";
    	}    	
    	if($this->isTestMode()) {
    		$this->form_action_url 	= 'https://test.barclaycardsmartpay.com/hpp/' . $landing_page;
    	} else {
    		$this->form_action_url 	= 'https://live.barclaycardsmartpay.com/hpp/' . $landing_page;
    	}
    }

    // class methods
    function update_status() {
      global $order, $db;

      if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_EPDQ_ZONE > 0) ) {
        $check_flag = false;
        $check = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_EPDQ_ZONE . "' and zone_country_id = '" . $order->delivery['country']['id'] . "' order by zone_id");
        while (!$check->EOF) {
          if ($check->fields['zone_id'] < 1) {
            $check_flag = true;
            break;
          } elseif ($check->fields['zone_id'] == $order->delivery['zone_id']) {
            $check_flag = true;
            break;
          }
          $check->MoveNext();
        }

        if ($check_flag == false) {
          $this->enabled = false;
        }
      }

      // disable the module if the order only contains virtual products
      if ($this->enabled == true) {
        if ($order->content_type != 'physical') {
          $this->enabled = false;
        }
      }
    }

    function javascript_validation() {
      return false;
    }

    function selection() {
      return array('id' => $this->code,
                   'module' => $this->title);
    }

    function pre_confirmation_check() {
      return false;
    }

    function confirmation() {
      return false;
    }

    function process_button() {
        global $customer_id, $order, $currencies;

    	$epdq_orderID = $customer_id . 'AT' . date('YmdHis');
    	$epdq_skinCode = MODULE_PAYMENT_EPDQ_SKIN;
    	$epdq_merchantAccount = MODULE_PAYMENT_EPDQ_MERCHANTACCOUNT;
    	$epdq_amount = number_format($order->info['total'] * $order->info['currency_value'], 0, '', '');
    	$epdq_currency = $order->info['currency'];
    	$epdq_shipbefore = date('Y-m-d',  mktime(0, 0, 0, date("m")  , date("d")+MODULE_PAYMENT_EPDQ_SHIPBEFORE, date("Y")));
    	$epdq_countryCode = MODULE_PAYMENT_EPDQ_COUNTRY;
    	$epdq_shopperEmail = $order->customer['email_address'];
    	$epdq_shopperReference = $customer_id;
    	
    	// for PHP4 and PHP5 < 5.13, DATE_ATOM is not defined
    	if(DATE_ATOM == "DATE_ATOM") {	
    		$dateformat = "Y-m-d\TH:i:s\Z";
    	} else {
    		$dateformat = DATE_ATOM;
    	}
    	
    	$epdq_sessionValidity =  gmdate($dateformat, time() + MODULE_PAYMENT_EPDQ_SESSIONVALID);
        //$epdq_sessionValidity =  "2012-05-23T17:30:09Z";
        
    	
    	$epdq_locale = MODULE_PAYMENT_EPDQ_LANGUAGE;
    
    	$process_button_string = "\n" .
    							 zen_draw_hidden_field('merchantReference', $epdq_orderID) . "\n" .
    							 zen_draw_hidden_field('paymentAmount', $epdq_amount) . "\n" .
    							 zen_draw_hidden_field('currencyCode', $epdq_currency) . "\n" .
    							 zen_draw_hidden_field('shipBeforeDate', $epdq_shipbefore) . "\n" .
    							 zen_draw_hidden_field('sessionValidity', $epdq_sessionValidity) . "\n" .
    							 zen_draw_hidden_field('skinCode', $epdq_skinCode) . "\n" .
    							 zen_draw_hidden_field('merchantAccount', $epdq_merchantAccount) . "\n" .
    							 zen_draw_hidden_field('shopperLocale', $epdq_locale) . "\n" .
    							 zen_draw_hidden_field('shopperEmail', $epdq_shopperEmail) . "\n" .
    							 zen_draw_hidden_field('shopperReference', $epdq_shopperReference);
    
    	$sign = $epdq_amount . $epdq_currency . $epdq_shipbefore .  $epdq_orderID . $epdq_skinCode .  $epdq_merchantAccount 
    			. $epdq_sessionValidity . $epdq_shopperEmail . $epdq_shopperReference;
     	
    	if($this->isTestMode()) {
    		$process_button_string .= zen_draw_hidden_field('merchantSig', base64_encode(pack('H*',$this->hmacsha1(MODULE_PAYMENT_EPDQ_HMAC_STRING_TEST,$sign))) ) . "\n";            
    	} else {
    		$process_button_string .= zen_draw_hidden_field('merchantSig', base64_encode(pack('H*',$this->hmacsha1(MODULE_PAYMENT_EPDQ_HMAC_STRING_LIVE,$sign))) ) . "\n";
    	}
    	
    	if($epdq_countryCode != "--") {
    		$process_button_string .= zen_draw_hidden_field('countryCode', $epdq_countryCode) . "\n";
    	}
    	
    	return $process_button_string;
    }

    function before_process() {
        global $order;
    
        $authResult = $_GET['authResult'];
        $pspReference = $_GET['pspReference'];
        $merchantReference  = $_GET['merchantReference'];
        $skinCode  = $_GET['skinCode'];
        $merchantSig  = $_GET['merchantSig'];
        
        $verifiedHash = false;
        
        $responseArray = array();
        $responseArray = $_GET;
        
        // Send the test information to the notify email
    	//if($this->isTestMode()) $this->sendNotifyEmail("Test Transaction", $responseArray);
        
        // No signature -> no payment
        if(!empty($merchantSig)) {  
          $sign = $authResult . $pspReference . $merchantReference . $skinCode;
          if($this->isTestMode()) {
    	  	$computedSig = base64_encode(pack('H*',$this->hmacsha1(MODULE_PAYMENT_EPDQ_HMAC_STRING_TEST,$sign)));
    	  } else {
    	  	$computedSig = base64_encode(pack('H*',$this->hmacsha1(MODULE_PAYMENT_EPDQ_HMAC_STRING_LIVE,$sign)));
    	  }
    	  if($computedSig == $merchantSig) {
    	  	$verifiedHash = true;
    	  }
        }
        
        if($verifiedHash == false) {
        	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode("HMAC_INVALID"), 'SSL', true, false));
        }
        
        if($authResult == "REFUSED") {
        	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode("REFUSED"), 'SSL', true, false));
        };
        
        if($authResult == "PENDING") {
        	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode("PENDING"), 'SSL', true, false));
        };
        
        if($authResult == "AUTHORISED") {
        	$order->info['cc_number'] = $pspReference;
        	$this->sendNotifyEmail("Authorised", $responseArray);
        } else {
        	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode("ERROR"), 'SSL', true, false));
        }

    }

    function after_process() {
      return false;
    }

    
    function check() {
      global $db;
      if (!isset($this->_check)) {
        $check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_EPDQ_STATUS'");
        $this->_check = $check_query->RecordCount();
      }
      return $this->_check;
    }

    function install() {
      global $db;
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable ePDQ Payment Module', 'MODULE_PAYMENT_EPDQ_STATUS', 'True', 'Do you want to enable the ePDQ CPI module?', '6', '1', 'zen_cfg_select_option(array(\\'True\\', \\'False\\'), ', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_EPDQ_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '2', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_EPDQ_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_EPDQ_ORDER_STATUS_ID', '0', 'Set the status of orders made with this payment module to this value', '6', '3', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Client Id', 'MODULE_PAYMENT_EPDQ_CLIENT_ID', '', 'Set the Client Id provided by Barclaycard to you', '6', '4', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Passphase', 'MODULE_PAYMENT_EPDQ_PASSPHASE', '', 'Set the Passphase that you have set on the epdq cpi admin', '6', '5', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Display Name', 'MODULE_PAYMENT_EPDQ_DISPLAY_NAME', '', 'Set the display name you want to see on the ePDQ pages', '6', '6', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Charge Type', 'MODULE_PAYMENT_EPDQ_CHARGE_TYPE', 'Auth', 'Set the display name you want to see on the ePDQ pages', '6', '7', 'zen_cfg_select_option(array(\\'Auth\\', \\'PreAuth\\'), ', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Card Types', 'MODULE_PAYMENT_EPDQ_SUPPORTED_CARD_TYPES', '125', '127 for all cards. 125 to exclude Amex only. See ePDQ integration guide for other option', '6', '8', now())");
      $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Delivery Address', 'MODULE_PAYMENT_EPDQ_COLLECT_DELIVERY_ADDRESS', '0', '0 to suppress delivery address in ePDQ or 1 to display it', '6', '9', 'zen_cfg_select_option(array(\\'0\\', \\'1\\'), ', now())");
    }

    function remove() {
      global $db;
      $db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
    }

    function keys() {
      return array('MODULE_PAYMENT_EPDQ_STATUS', 'MODULE_PAYMENT_EPDQ_ZONE', 'MODULE_PAYMENT_EPDQ_ORDER_STATUS_ID', 'MODULE_PAYMENT_EPDQ_SORT_ORDER', 'MODULE_PAYMENT_EPDQ_CLIENT_ID','MODULE_PAYMENT_EPDQ_PASSPHASE', 'MODULE_PAYMENT_EPDQ_DISPLAY_NAME', 'MODULE_PAYMENT_EPDQ_CHARGE_TYPE', 'MODULE_PAYMENT_EPDQ_SUPPORTED_CARD_TYPES', 'MODULE_PAYMENT_EPDQ_COLLECT_DELIVERY_ADDRESS');
    }
    
    /**
	* Returns immediately with whether this is operating in test mode
	* References defined variable MODULE_PAYMENT_EPDQ_MODE which
	* should be configured in the administration panel.
	* @return boolean Test Mode check
	*/
	function isTestMode() {
		if(MODULE_PAYMENT_EPDQ_MODE == "Live") {
			return false;
		}
	return true; // Default to running test mode
	}

	function isOnePagePayment() {
		 if(MODULE_PAYMENT_EPDQ_ONEPAGE == "Single Page") {
		 	return true;
		 }
		 return false;
	}
    /**
	 * Create an array that represents the possible module errors
	 * @return Array Errors that have arrived from HTTP
	 */
	function get_error() {
		global $HTTP_GET_VARS, $language;

		// ensure we have all texts defined
		require_once(DIR_WS_LANGUAGES . $language . '/modules/payment/'.$this->code.'.php');

		$error = '';
		
		if(isset($HTTP_GET_VARS['error'])) {
			$error = urldecode($HTTP_GET_VARS['error']); // otherwise default error is displayed	
		}
		
		switch($error) {
			case 'REFUSED':
				$error_text['title'] = MODULE_PAYMENT_EPDQ_TEXT_REFUSED;
				$error_text['error'] = MODULE_PAYMENT_EPDQ_TEXT_REFUSED_DESCRIPTION;
				break;
			case 'HMAC_INVALID':
				$error_text['title'] = MODULE_PAYMENT_EPDQ_TEXT_HMAC_INVALID;
				$error_text['error'] = MODULE_PAYMENT_EPDQ_TEXT_HMAC_INVALID_DESCRIPTION;
				break;
			default: //other error
				$error_text['title'] = MODULE_PAYMENT_EPDQ_TEXT_ERROR;
				$error_text['error'] = MODULE_PAYMENT_EPDQ_TEXT_ERROR_DESCRIPTION;
				break;
	    	}
	   	return $error_text;
	}
    
    
	//Calculate HMAC-SHA1 according to RFC2104
	// http://www.ietf.org/rfc/rfc2104.txt
	function hmacsha1($key,$data) {
	    $blocksize=64;
	    $hashfunc='sha1';
	    if (strlen($key)>$blocksize)
	        $key=pack('H*', $hashfunc($key));
	    $key=str_pad($key,$blocksize,chr(0x00));
	    $ipad=str_repeat(chr(0x36),$blocksize);
	    $opad=str_repeat(chr(0x5c),$blocksize);
	    $hmac = pack(
	                'H*',$hashfunc(
	                    ($key^$opad).pack(
	                        'H*',$hashfunc(
	                            ($key^$ipad).$data
	                        )
	                    )
	                )
	            );
	    return bin2hex($hmac);
	}
    
    /**
	 * Returns with the Email to Notify of Transaction Errors
	 * @return String Email address of Account Admin
	 */
	function getNotifyEmailAddress() {
		/*
        if(defined('MODULE_PAYMENT_EPDQ_EMAIL') && tep_validate_email(MODULE_PAYMENT_EPDQ_EMAIL)) {
			return MODULE_PAYMENT_EPDQ_EMAIL;
		} else {
			if(defined('STORE_OWNER_EMAIL_ADDRESS') && tep_validate_email(STORE_OWNER_EMAIL_ADDRESS)) {
				return STORE_OWNER_EMAIL_ADDRESS;
			}
		}
		return null; // No valid email specified
        */
	}
	/**
	 * Sends an email alert to the Admins email address
	 * @param String $error Verbose Error
	 */
	function sendNotifyEmail($error, &$responseArray) {
		/*
        global $order;
		$notifyAddress = $this->getNotifyEmailAddress();
		if (!empty($notifyAddress)) {
			$subject = $error;
			$message = 'Notication:' . "\n\n";
			$message .= $error . "\n\n";
			$message .= 'Payment Details' . "\n\n";
			$message .= "Adyen Result:\n";
			foreach($responseArray as $key => $value) $message .= $key . '=' . $value . "\n";
			$message .= "\n\nORDER CUSTOMER:\n";
			foreach($order->customer as $key => $value) $message .= $key . '='. $value . "\n";
			$message .= "\n\nSERVER VARS:\n";
			foreach($_SERVER as $key => $value) $message .= $key . '='. $value . "\n";
			tep_mail('', $notifyAddress, $subject, $message, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, '');
		}
        */
	}
  }
